/******************************************************************************\
    ClientDataBase.h discribes a database of clients.
    It's used for acm server. See main.cpp for details.
    Copyright (C) 2008  Victor Vinogradov (fly3333@gmail.com)

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
\******************************************************************************/

#pragma once 

#include ".\BaseDataBase.hpp"

namespace nsClientDataBase
{
	struct sClientData0
	{
		unsigned long Key;
		unsigned long Ip;
		unsigned short Port;
		unsigned long long Time;
	};

	struct sClientData1
	{
		unsigned long Key;
		unsigned long Ip;
		unsigned short Port;
		unsigned long ContestantId;
		unsigned long long Time;
	};

	typedef sClientData1 sClientData;

	void ConversionFunction0( void *new_data, const void *prev_data );

	const sConversionTable ConversionTable[] =
	{
		{ sizeof( sClientData0 ), sizeof( sClientData1 ), &ConversionFunction0 }
	};

	struct IpPortCompare : public std::binary_function< cDataPointer< sClientData >, cDataPointer< sClientData >, bool >
	{
		bool operator()( const cDataPointer< sClientData > &left, const cDataPointer< sClientData > &right ) const
		{
			return left->Ip < right->Ip ||
				left->Ip == right->Ip && left->Port < right->Port;
		}
	};

	struct TimeCompare : public std::binary_function< cDataPointer< sClientData >, cDataPointer< sClientData >, bool >
	{
		bool operator()( const cDataPointer< sClientData > &left, const cDataPointer< sClientData > &right ) const
		{
			return left->Time < right->Time ||
				left->Time == right->Time && left->Key < right->Key;
		}
	};

	typedef cBaseDataBase< sClientData >::KeyIterator KeyIterator;
	typedef cPublicIterator< sClientData, IpPortCompare > IpPortIterator;
	typedef cPublicIterator< sClientData, TimeCompare > TimeIterator;

	class cWardClientDataBase : public cBaseDataBase< sClientData >
	{
	private:
		std::set< cDataPointer< sClientData >, IpPortCompare > IpPortIndex;
		std::set< cDataPointer< sClientData >, TimeCompare > TimeIndex;
	protected:
		virtual bool Indexed( const cDataPointer< sClientData > &data_pointer )
		{
			//return IpPortIndex.find( data_pointer ) != IpPortIndex.end() ||
			//	TimeIndex.find( data_pointer ) != TimeIndex.end();
			return IpPortIndex.find( data_pointer ) != IpPortIndex.end();
		}
		virtual void InsertIndex( const cDataPointer< sClientData > &data_pointer )
		{
			IpPortIndex.insert( data_pointer );
			TimeIndex.insert( data_pointer );
		}
		virtual void UpdateIndex( const cDataPointer< sClientData > &data_pointer, unsigned long index ) 
		{
			IpPortIndex.find( data_pointer )->Index = index;
			TimeIndex.find( data_pointer )->Index = index;
		}
		virtual void DeleteIndex( const cDataPointer< sClientData > &data_pointer ) 
		{
			IpPortIndex.erase( data_pointer );
			TimeIndex.erase( data_pointer );
		}
		virtual void ClearIndex()
		{
			IpPortIndex.clear();
			TimeIndex.clear();
		}
	public:
		cWardClientDataBase(/* bool auto_update */)
			: cBaseDataBase( /*auto_update*/ )
		{
		}
		IpPortIterator BeginByIpPort() const 
		{
			return IpPortIterator( IpPortIndex.begin() );
		}
		IpPortIterator FindByIpPort( unsigned long ip, unsigned short port ) const 
		{
			sClientData client_data;
			client_data.Ip = ip;
			client_data.Port = port;
			return IpPortIterator( IpPortIndex.find( cDataPointer< sClientData >( &client_data ) ) );
		}
		IpPortIterator EndByIpPort() const
		{
			return IpPortIterator( IpPortIndex.end() );
		}
		TimeIterator BeginByTime() const
		{
			return TimeIterator( TimeIndex.begin() );
		}
		TimeIterator EndByTime() const
		{
			return TimeIterator( TimeIndex.end() );
		}
	};

	class cClientDataBase : public cPointerObject< cWardClientDataBase >
	{
	public:
		bool Create( /*bool auto_update = false*/ )
		{
			cWardClientDataBase *ward_client_data_base;
			try
			{
				ward_client_data_base = new cWardClientDataBase( /*auto_update*/ );
			}
			catch( ... )
			{
				return false;
			}
			if( !SwitchToWardObject( ward_client_data_base ) )
			{
				delete ward_client_data_base;
				return false;
			}
			return true;
		}
		void Destroy()
		{
			SwitchToSubObject( NULL );
		}
	};
}
